{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Fast Sign Adversary Generation Example\n",
    "\n",
    "This notebook demos find adversary example by using symbolic API and integration with Numpy",
    "\n",
    "Reference: \n",
    "\n",
    "[1] Goodfellow, Ian J., Jonathon Shlens, and Christian Szegedy. \"Explaining and harnessing adversarial examples.\" arXiv preprint arXiv:1412.6572 (2014)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import mxnet as mx\n",
    "import numpy as np\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import matplotlib.cm as cm\n",
    "\n",
    "from data import mnist_iterator"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Build Network\n",
    "\n",
    "note: in this network, we will calculate softmax, gradient in numpy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dev = mx.gpu()\n",
    "batch_size = 100\n",
    "train_iter, val_iter = mnist_iterator(batch_size=batch_size, input_shape = (1,28,28))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# input\n",
    "data = mx.symbol.Variable('data')\n",
    "# first conv\n",
    "conv1 = mx.symbol.Convolution(data=data, kernel=(5,5), num_filter=20)\n",
    "tanh1 = mx.symbol.Activation(data=conv1, act_type=\"tanh\")\n",
    "pool1 = mx.symbol.Pooling(data=tanh1, pool_type=\"max\",\n",
    "                          kernel=(2,2), stride=(2,2))\n",
    "# second conv\n",
    "conv2 = mx.symbol.Convolution(data=pool1, kernel=(5,5), num_filter=50)\n",
    "tanh2 = mx.symbol.Activation(data=conv2, act_type=\"tanh\")\n",
    "pool2 = mx.symbol.Pooling(data=tanh2, pool_type=\"max\",\n",
    "                          kernel=(2,2), stride=(2,2))\n",
    "# first fullc\n",
    "flatten = mx.symbol.Flatten(data=pool2)\n",
    "fc1 = mx.symbol.FullyConnected(data=flatten, num_hidden=500)\n",
    "tanh3 = mx.symbol.Activation(data=fc1, act_type=\"tanh\")\n",
    "# second fullc\n",
    "fc2 = mx.symbol.FullyConnected(data=tanh3, num_hidden=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def Softmax(theta):\n",
    "    max_val = np.max(theta, axis=1, keepdims=True)\n",
    "    tmp = theta - max_val\n",
    "    exp = np.exp(tmp)\n",
    "    norm = np.sum(exp, axis=1, keepdims=True)\n",
    "    return exp / norm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def LogLossGrad(alpha, label):\n",
    "    grad = np.copy(alpha)\n",
    "    for i in range(alpha.shape[0]):\n",
    "        grad[i, label[i]] -= 1.\n",
    "    return grad"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Prepare useful data for the network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "data_shape = (batch_size, 1, 28, 28)\n",
    "arg_names = fc2.list_arguments() # 'data' \n",
    "arg_shapes, output_shapes, aux_shapes = fc2.infer_shape(data=data_shape)\n",
    "\n",
    "arg_arrays = [mx.nd.zeros(shape, ctx=dev) for shape in arg_shapes]\n",
    "grad_arrays = [mx.nd.zeros(shape, ctx=dev) for shape in arg_shapes]\n",
    "reqs = [\"write\" for name in arg_names]\n",
    "\n",
    "model = fc2.bind(ctx=dev, args=arg_arrays, args_grad = grad_arrays, grad_req=reqs)\n",
    "arg_map = dict(zip(arg_names, arg_arrays))\n",
    "grad_map = dict(zip(arg_names, grad_arrays))\n",
    "data_grad = grad_map[\"data\"]\n",
    "out_grad = mx.nd.zeros(model.outputs[0].shape, ctx=dev)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Init weight "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "for name in arg_names:\n",
    "    if \"weight\" in name:\n",
    "        arr = arg_map[name]\n",
    "        arr[:] = mx.rnd.uniform(-0.07, 0.07, arr.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def SGD(weight, grad, lr=0.1, grad_norm=batch_size):\n",
    "    weight[:] -= lr * grad / batch_size\n",
    "\n",
    "def CalAcc(pred_prob, label):\n",
    "    pred = np.argmax(pred_prob, axis=1)\n",
    "    return np.sum(pred == label) * 1.0\n",
    "\n",
    "def CalLoss(pred_prob, label):\n",
    "    loss = 0.\n",
    "    for i in range(pred_prob.shape[0]):\n",
    "        loss += -np.log(max(pred_prob[i, label[i]], 1e-10))\n",
    "    return loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Train a network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train Accuracy: 0.92\t Train Loss: 0.28077\n",
      "Train Accuracy: 0.97\t Train Loss: 0.08434\n",
      "Train Accuracy: 0.98\t Train Loss: 0.05849\n",
      "Train Accuracy: 0.99\t Train Loss: 0.04577\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.4/dist-packages/ipykernel/__main__.py:11: DeprecationWarning: using a non-integer number instead of an integer will result in an error in the future\n",
      "/usr/local/lib/python3.4/dist-packages/ipykernel/__main__.py:4: DeprecationWarning: using a non-integer number instead of an integer will result in an error in the future\n"
     ]
    }
   ],
   "source": [
    "num_round = 4\n",
    "train_acc = 0.\n",
    "nbatch = 0\n",
    "for i in range(num_round):\n",
    "    train_loss = 0.\n",
    "    train_acc = 0.\n",
    "    nbatch = 0\n",
    "    train_iter.reset()\n",
    "    for data, label in train_iter:\n",
    "        arg_map[\"data\"][:] = data\n",
    "        model.forward(is_train=True)\n",
    "        theta = model.outputs[0].asnumpy()\n",
    "        alpha = Softmax(theta)\n",
    "        train_acc += CalAcc(alpha, label.asnumpy()) / batch_size\n",
    "        train_loss += CalLoss(alpha, label.asnumpy()) / batch_size\n",
    "        losGrad_theta = LogLossGrad(alpha, label.asnumpy())\n",
    "        out_grad[:] = losGrad_theta\n",
    "        model.backward([out_grad])\n",
    "        # data_grad[:] = grad_map[\"data\"]\n",
    "        for name in arg_names:\n",
    "            if name != \"data\":\n",
    "                SGD(arg_map[name], grad_map[name])\n",
    "        \n",
    "        nbatch += 1\n",
    "    #print(np.linalg.norm(data_grad.asnumpy(), 2))\n",
    "    train_acc /= nbatch\n",
    "    train_loss /= nbatch\n",
    "    print(\"Train Accuracy: %.2f\\t Train Loss: %.5f\" % (train_acc, train_loss))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get pertubation by using fast sign method, check validation change"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Val Batch Accuracy:  1.0\n",
      "Val Batch Accuracy after pertubation:  0.04\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.4/dist-packages/ipykernel/__main__.py:4: DeprecationWarning: using a non-integer number instead of an integer will result in an error in the future\n"
     ]
    }
   ],
   "source": [
    "val_iter.reset()\n",
    "data, label = val_iter.next()\n",
    "arg_map[\"data\"][:] = data\n",
    "model.forward(is_train=True)\n",
    "theta = model.outputs[0].asnumpy()\n",
    "alpha = Softmax(theta)\n",
    "print(\"Val Batch Accuracy: \", CalAcc(alpha, label.asnumpy()) / batch_size)\n",
    "#########\n",
    "grad = LogLossGrad(alpha, label.asnumpy())\n",
    "out_grad[:] = grad\n",
    "model.backward([out_grad])\n",
    "noise = np.sign(data_grad.asnumpy())\n",
    "arg_map[\"data\"][:] = data.asnumpy() + 0.15 * noise\n",
    "model.forward(is_train=True)\n",
    "raw_output = model.outputs[0].asnumpy()\n",
    "pred = Softmax(raw_output)\n",
    "print(\"Val Batch Accuracy after pertubation: \", CalAcc(pred, label.asnumpy()) / batch_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Visualize example after pertubation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "true: 9\n",
      "pred: 8\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f16709a6128>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import random as rnd\n",
    "idx = rnd.randint(0, 99)\n",
    "images = data.asnumpy()  + 0.15 * noise\n",
    "plt.imshow(images[idx, :].reshape(28,28), cmap=cm.Greys_r)\n",
    "print(\"true: %d\" % label.asnumpy()[idx])\n",
    "print(\"pred: %d\" % np.argmax(pred, axis=1)[idx])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
